package api

import (
	"github.com/360EntSecGroup-Skylar/excelize"
	"github.com/gin-gonic/gin"
	"github.com/tealeg/xlsx"
	"go.uber.org/zap"
	"path/filepath"
	"seat-service/initialization"
	"seat-service/model"
	"seat-service/model/dto"
	"seat-service/response"
	service "seat-service/service/impl"
	"strconv"
	"time"
)

type BuildingsAdminApi struct {
}

var buildingsAdminService service.BuildingsAdminService

// QueryBuildByCondition 查询出符合条件的楼栋
func (b *BuildingsAdminApi) QueryBuildByCondition(context *gin.Context) {
	var conditions dto.AdminQueryBuildCondition
	if err := context.ShouldBindJSON(&conditions); err != nil {
		initialization.SeatLogger.Error("context.ShouldBindJSON(&condition) is failed", zap.Error(err))
		resp.Fail(context, response.CodeParamError, nil)
		return
	}
	count, buildingsInformation, err := buildingsAdminService.SelectBuildingsByCondition(conditions)
	if err != nil {
		initialization.SeatLogger.Error(" buildingsAdminService.SelectBuildingsByCondition(condition) is failed", zap.Error(err))
		resp.Fail(context, response.CodeServerBusy, nil)
		return
	}
	respData := struct {
		Build []dto.BuildInformation `json:"build"`
		Total int64                  `json:"total"`
	}{
		Build: buildingsInformation,
		Total: count,
	}
	resp.Success(context, response.CodeSuccess, respData)
}

// AddNewBuild 管理员新增楼栋
func (b *BuildingsAdminApi) AddNewBuild(context *gin.Context) {
	var newBuild dto.NewBuildInformation
	if err := context.ShouldBindJSON(&newBuild); err != nil {
		initialization.SeatLogger.Error("context.ShouldBindJSON(&newBuild) is failed", zap.Error(err))
		resp.Fail(context, response.CodeParamError, nil)
		return
	}
	err := buildingsAdminService.AddBuilding(newBuild)
	if err != nil {
		initialization.SeatLogger.Error("buildingsAdminService.AddBuilding(newBuild) is failed", zap.Error(err))
		if err.Error() == "CampusIsNotExist" {
			resp.Fail(context, response.CampusNoExists, nil)
			return
		} else if err.Error() == "BuildExists" {
			resp.Fail(context, response.BuildIsExist, nil)
			return
		}
		resp.Fail(context, response.BuildIsExist, nil)
		return
	}
	resp.Success(context, response.CodeSuccess, nil)
}

// QueryBuildById 根据id 查询楼栋
func (b *BuildingsAdminApi) QueryBuildById(context *gin.Context) {
	params := context.Params
	buildId, err := strconv.Atoi(params.ByName("build_id"))
	if err != nil {
		initialization.SeatLogger.Error("context.ShouldBindUri(&buildId) is failed", zap.Error(err))
		resp.Fail(context, response.CodeParamError, nil)
		return
	}
	buildInformation, err := buildingsAdminService.SelectBuildById(buildId)
	if err != nil {
		initialization.SeatLogger.Error("buildingsAdminService.SelectBuildById(buildId) is failed", zap.Error(err))
		resp.Fail(context, response.CodeServerBusy, nil)
		return
	}
	resp.Success(context, response.CodeSuccess, buildInformation)
}

// ChangeBuildInformation 修改楼栋信息
func (b *BuildingsAdminApi) ChangeBuildInformation(context *gin.Context) {
	var updateInformation dto.UpdateBuildParams
	if err := context.ShouldBindJSON(&updateInformation); err != nil {
		initialization.SeatLogger.Error("context.ShouldBindJSON(&updateInformation) is failed", zap.Error(err))
		resp.Fail(context, response.CodeParamError, nil)
		return
	}
	newBuildInformation, err := buildingsAdminService.UpdateBuildData(updateInformation)
	if err != nil {
		initialization.SeatLogger.Error(" buildingsAdminService.UpdateBuildData(updateInformation) is failed", zap.Error(err))
		resp.Fail(context, response.CodeServerBusy, nil)
		return
	}
	resp.Success(context, response.CodeSuccess, newBuildInformation)
}

// DeleteBuildByIds 删除楼栋
func (b *BuildingsAdminApi) DeleteBuildByIds(context *gin.Context) {
	var buildIds dto.DeleteIds
	if err := context.ShouldBindJSON(&buildIds); err != nil {
		initialization.SeatLogger.Error("context.ShouldBindJSON(&buildIds) is failed", zap.Error(err))
		resp.Fail(context, response.CodeParamError, nil)
		return
	}
	err := buildingsAdminService.DeleteByIds(buildIds)
	if err != nil {
		initialization.SeatLogger.Error("buildingsAdminService.DeleteByIds(buildIds) is failed", zap.Error(err))
		resp.Fail(context, response.CodeServerBusy, nil)
		return
	}
	resp.Success(context, response.CodeSuccess, nil)
}

// GetAllCampusInformations 得到所有校区信息
func (b *BuildingsAdminApi) GetAllCampusInformations(context *gin.Context) {
	allCampusInformation, err := buildingsAdminService.SelectAllCampus()
	if err != nil {
		initialization.SeatLogger.Error("buildingsAdminService.SelectAllCampus() is failed", zap.Error(err))
		resp.Fail(context, response.CodeParamError, nil)
		return
	}
	resp.Success(context, response.CodeSuccess, allCampusInformation)
}

// GetCampusIdByName 根据校区名字得到校区id
func (b *BuildingsAdminApi) GetCampusIdByName(context *gin.Context) {
	campusName := context.Query("campus_name")
	campusId, err := buildingsAdminService.SelectCampusIdByName(campusName)
	if err != nil {
		initialization.SeatLogger.Error("buildingsAdminService.SelectCampusIdByName(campusName) is failed", zap.Error(err))
		resp.Fail(context, response.CodeServerBusy, nil)
		return
	}
	resp.Success(context, response.CodeSuccess, campusId)
}

// AnalysisData 解析Excel表,将数据导入到数据库
func (b *BuildingsAdminApi) AnalysisData(context *gin.Context) {
	buildExcel, err := context.FormFile("build")
	if err != nil {
		initialization.SeatLogger.Error("context.FormFile(\"build\") is failed", zap.Error(err))
		resp.Fail(context, response.UploadFileFail, nil)
		return
	}
	//将上传的文件保存到 uploads/excel目录下面
	filePath := filepath.Join("uploads", "excel", buildExcel.Filename)
	if err := context.SaveUploadedFile(buildExcel, filePath); err != nil {
		initialization.SeatLogger.Error("context.SaveUploadedFile(buildExcel , filePath) is failed", zap.Error(err))
		resp.Fail(context, response.UploadFileFail, nil)
		return
	}
	//解析Excel文件
	buildXlsx, err := excelize.OpenFile(filePath)
	if err != nil {
		initialization.SeatLogger.Error("excelize.OpenFile(filePath) is failed", zap.Error(err))
		resp.Fail(context, response.UploadFileFail, nil)
		return
	}
	//获取excel中具体的列的值
	rows := buildXlsx.GetRows("Sheet" + "1")
	//循环遍历
	var newBulidInformations []model.Building
	for _, row := range rows {
		status := 1
		if row[4] == "锁定" {
			status = 0
		}
		//转化时间格式
		layout := "1/2/06 15:04"
		var lockStartTime, lockEndTime *time.Time
		if row[2] != "" {
			parsedTime, _ := time.Parse(layout, row[2])
			lockStartTime = &parsedTime
		}
		if row[3] != "" {
			parsedTime, _ := time.Parse(layout, row[3])
			lockEndTime = &parsedTime
		}
		var longitude, latitude float64
		if row[5] != "" {
			longitude, err = strconv.ParseFloat(row[5], 64)
			if err != nil {
				continue
			}
		}
		if row[6] != "" {
			latitude, err = strconv.ParseFloat(row[5], 64)
			if err != nil {
				continue
			}
		}
		// 根据校区名称 得到校区id
		campusId, _ := buildingsAdminService.SelectCampusIdByName(row[1])
		if campusId == 0 { //校区不存在,不插入
			continue
		}
		newBuildInformation := model.Building{
			Name:           row[0],         //教学楼名称
			CampusId:       uint(campusId), //校区id
			BuildingStatus: status,         //楼栋状态
			LockStartTime:  lockStartTime,
			LockEndTime:    lockEndTime,
			Longitude:      longitude,
			Latitude:       latitude,
		}
		newBulidInformations = append(newBulidInformations, newBuildInformation)
	}
	newBulidInformations = newBulidInformations[1:]
	errBuildInformation, err := buildingsAdminService.InsertExcelBuildInformations(newBulidInformations)
	if err != nil {
		initialization.SeatLogger.Error("buildingsAdminService.InsertExcelBuildInformations(newBulidInformations) is error", zap.Error(err))
		resp.Fail(context, response.CodeServerBusy, errBuildInformation)
	}
	resp.Success(context, response.CodeSuccess, errBuildInformation)
}

// ExportBuildTemplate 导出数据模板
func (b *BuildingsAdminApi) ExportBuildTemplate(context *gin.Context) {
	file := xlsx.NewFile()

	//添加一个工作表
	sheet, err := file.AddSheet("Sheet1")
	if err != nil {
		initialization.SeatLogger.Error("file.AddSheet(\"Sheet1\") is error", zap.Error(err))
		resp.Fail(context, response.GetFileFail, nil)
		return
	}
	//添加一个标题行
	titles := sheet.AddRow()
	titles.AddCell().SetValue("教学楼名称")
	titles.AddCell().SetValue("校区名称")
	titles.AddCell().SetValue("校区锁定开始时间")
	titles.AddCell().SetValue("校区锁定结束时间")
	titles.AddCell().SetValue("楼栋状态")
	titles.AddCell().SetValue("楼栋经度")
	titles.AddCell().SetValue("楼栋纬度")
	//创建示例行
	row := sheet.AddRow()
	row.AddCell().SetValue("零号楼(模板)")
	row.AddCell().SetValue("西区/东区/新东区")
	row.AddCell().SetValue("2006-01-01 15:30 / 时间为空也可")
	row.AddCell().SetValue("2006-01-01 15:30 / 时间为空也可")
	row.AddCell().SetValue("正常 / 锁定")
	row.AddCell().SetValue("经度")
	row.AddCell().SetValue("纬度")
	//设置 HTTP 头部
	context.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
	context.Header("Content-Disposition", "attachment; filename=楼栋信息.xlsx")
	//将Excel文件返回给前端
	if err := file.Write(context.Writer); err != nil {
		initialization.SeatLogger.Error("xlsx.Write(context.Writer) is error", zap.Error(err))
		resp.Fail(context, response.GetFileFail, nil)
		return
	}
}
